package info.unlp.tesis.plugin.wizard;


import info.unlp.tesis.plugin.style.JavaLineStyler;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.m2m.atl.core.IExtractor;
import org.eclipse.m2m.atl.core.IInjector;
import org.eclipse.m2m.atl.core.IModel;
import org.eclipse.m2m.atl.core.IReferenceModel;
import org.eclipse.m2m.atl.core.ModelFactory;
import org.eclipse.m2m.atl.core.emf.EMFExtractor;
import org.eclipse.m2m.atl.core.emf.EMFInjector;
import org.eclipse.m2m.atl.core.launch.ILauncher;
import org.eclipse.m2m.atl.core.service.CoreService;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.osgi.framework.Bundle;
/**
 * Pagina del wizard donde, a partir de un modelo QVT dado y una transformacion escrita en ATL, genera el equivalente modelo en lambda. 
 * 
 * 
 * @author Carina Moldes
 *
 */
public class GenerateATLPage extends WizardPage {

	private static URL asmURL;
	
	private static IInjector injector;

	private static IExtractor extractor;

	private static IReferenceModel qvtMetamodel;
	
	private static IReferenceModel lambdaMetamodel;

	private StyledText styledText;
	
	private Bundle bundle;
	
    JavaLineStyler lineStyler = new JavaLineStyler();
	
	public GenerateATLPage(String pageName){
		super(pageName);
		setTitle("Obteniendo la transformacion.");
		setDescription("Presione <<Generar ATL>>.");
	}
	
	
	@Override
	public void createControl(Composite parent) {
		Composite container = new Composite(parent, SWT.NULL);
		GridLayout layout = new GridLayout();
		container.setLayout(layout);
		layout.numColumns = 1;
		layout.verticalSpacing = 9;

		Button generateATLButton = new Button(container, SWT.PUSH);
		generateATLButton.setText("Generar ATL");
		generateATLButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				handleGenerateATL();
			}
		});

		setControl(container);
		
	    styledText = new StyledText(container, SWT.BORDER | SWT.MULTI
				| SWT.V_SCROLL | SWT.H_SCROLL);

		GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL
				| GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
		gd.horizontalAlignment = GridData.FILL;
		gd.verticalAlignment = GridData.FILL;
		gd.horizontalSpan = 5;
		gd.verticalSpan = 20;

		gd.widthHint = 5;
		gd.heightHint = 20 * 10;

		styledText.setLayoutData(gd);
		
	}
	



	private void handleGenerateATL() {

	    bundle = Platform.getBundle("info.unlp.tesis.plugin"); //$NON-NLS-1$
		asmURL = bundle.getEntry("/transformation/qvt2Lambda.asm"); //$NON-NLS-1$
		injector = new EMFInjector();			
		extractor = new EMFExtractor();
		
		try {
			this.transform(null);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void transform(File file) throws Exception {
		
		ModelFactory factory = CoreService.getModelFactory("EMF"); //$NON-NLS-1$

		// Se toma el metamodelo de QVT  
		qvtMetamodel = factory.newReferenceModel();
     	URL transformationMetamodelURL = bundle.getEntry("Transformation.ecore"); //$NON-NLS-1$
		injector.inject(qvtMetamodel, transformationMetamodelURL.toString()); //$NON-NLS-1$
	
		// Se toma el metamodelo de Lambda
		lambdaMetamodel = factory.newReferenceModel();
		URL lambdaMetamodelURL = bundle.getEntry("Lambda.ecore"); //$NON-NLS-1$
		injector.inject(lambdaMetamodel, lambdaMetamodelURL.toString());
		
		// Se crea el launcher que ejecutara la transformacion
		ILauncher launcher = null;
		launcher = CoreService.getLauncher("EMF-specific VM"); //$NON-NLS-1$

		// Se crean los modelos a partir de los metamodelos
		IModel qvtModel = factory.newModel(qvtMetamodel);
		IModel lambdaModel = factory.newModel(lambdaMetamodel);

		// Se obtiene el modelo de qvt
		injector.inject(qvtModel, ((GenerateXMIPage)this.getPreviousPage()).getPath_qvt_model()); //$NON-NLS-1$
		
		// Se setean configuraciones al launcher
		Map<String, Object> options = new HashMap<String, Object>();
		options.put("allowInterModelReferences", "true");
		options.put("profile", "true");
		options.put("supportUML2Stereotypes", "true");
		launcher.initialize(options);
			
		// Se configura el launcher
		launcher.addInModel(qvtModel, "IN", "QVT"); //$NON-NLS-1$ //$NON-NLS-2$
		launcher.addOutModel(lambdaModel, "OUT", "Lambda");

		//se ejecuta la transformacion
		launcher.launch(ILauncher.RUN_MODE, new NullProgressMonitor(), 
				options, asmURL.openStream());

		// se ubica el modelo de salida, en la ubicacion dada
		extractor.extract(lambdaModel, "file:C:/lambda_model.xmi");
		
		// se muestra el contenido del archivo generado
		styledText.addLineStyleListener(lineStyler);
		BufferedReader reader = new BufferedReader(new FileReader("C:/lambda_model.xmi"));
		String linea = reader.readLine();
		while (linea != null)
		{  
		  styledText.append(linea);
		  styledText.append(System.getProperty("line.separator")); 
		  linea = reader.readLine();
		}
		
	
		
	}

}
